package com.hemerasolutions.v2trainer.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import com.hemerasolutions.v2trainer.dao.interfaces.StepDaoInterface;
import com.hemerasolutions.v2trainer.model.exercise.Exercise;
import com.hemerasolutions.v2trainer.model.exercise.Exercise_;
import com.hemerasolutions.v2trainer.model.exercise.TemplateExercise;
import com.hemerasolutions.v2trainer.model.exercise.TemplateExercise_;
import com.hemerasolutions.v2trainer.model.step.Step;
import com.hemerasolutions.v2trainer.model.step.Step_;
import com.hemerasolutions.v2trainer.model.step.substep.ExerciseGroupStep;
import com.hemerasolutions.v2trainer.model.step.substep.ExerciseGroupStep_;
import com.hemerasolutions.v2trainer.model.step.substep.ExerciseGroupedStep;
import com.hemerasolutions.v2trainer.model.step.substep.ExerciseGroupedStep_;
import com.hemerasolutions.v2trainer.model.step.substep.ExerciseStep;
import com.hemerasolutions.v2trainer.model.step.substep.ExerciseStep_;

import org.springframework.stereotype.Repository;


@Repository(value = "stepDao")
public class StepDao extends BaseDao<Step> implements StepDaoInterface {

	private static final long serialVersionUID = 1L;

	@Override
	public List<Step> searchSteps(Map<String, Object> fields) {

		List<Predicate> predicateList = new ArrayList<Predicate>();

		CriteriaBuilder cb = this.getEntityManager().getCriteriaBuilder();

		CriteriaQuery<Step> cq  = cb.createQuery(Step.class);
		
		Root<Step> step = cq.from(Step.class);
		

		Join<Step,ExerciseStep> joinExerciseStep = null;

		Join<Step,TemplateExercise> joinTemplate = null;

		Join<Step,ExerciseGroupStep> joinExerciseGroupStep = null;
		
		Join<Step,ExerciseGroupedStep> joinExerciseGroupedStep = null;

		Predicate pred;
		
	    for (Map.Entry<String,Object> line : fields.entrySet()) {
	    	
	    	if(line.getKey().toString().equals("exercise")){

	    		if(joinExerciseGroupedStep == null){
	    			joinExerciseGroupedStep = step.join(Step_.exerciseGroupedStep,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseStep == null){
	    			joinExerciseStep = step.join(Step_.exerciseStep,JoinType.LEFT);
	    		}
	    		
	    		pred = cb.or(	cb.equal(joinExerciseGroupedStep.get(ExerciseGroupedStep_.exercise), line.getValue())
	    						,cb.equal(joinExerciseStep.get(ExerciseStep_.exercise), line.getValue()));

	    		predicateList.add(pred);
	    		
	    	}else if(line.getKey().toString().equals("modality")){

	    		if(joinExerciseGroupedStep == null){
	    			joinExerciseGroupedStep = step.join(Step_.exerciseGroupedStep,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseStep == null){
	    			joinExerciseStep = step.join(Step_.exerciseStep,JoinType.LEFT);
	    		}
	    		

	    		if(joinTemplate == null){
	    			joinTemplate = step.join(Step_.templateExercise,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseGroupStep == null){
	    			joinExerciseGroupStep = step.join(Step_.exerciseGroupStep,JoinType.LEFT);
	    		}

	    		
	    		Path<Exercise> egsExercise = joinExerciseGroupedStep.get(ExerciseGroupedStep_.exercise);
	    		Path<Exercise> esExercise  = joinExerciseStep.get(ExerciseStep_.exercise);
	    				
	    				
	    		pred = cb.or(cb.equal(egsExercise.get(Exercise_.modality), line.getValue())
	    					,cb.equal(esExercise.get(Exercise_.modality), line.getValue())
	    					,cb.equal(joinTemplate.get(TemplateExercise_.modality), line.getValue())
	    					,cb.equal(joinExerciseGroupStep.get(ExerciseGroupStep_.modality), line.getValue()));

	    		predicateList.add(pred);

	    		
	    	}else if(line.getKey().toString().equals("intensityZone")){

	    		if(joinExerciseGroupedStep == null){
	    			joinExerciseGroupedStep = step.join(Step_.exerciseGroupedStep,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseStep == null){
	    			joinExerciseStep = step.join(Step_.exerciseStep,JoinType.LEFT);
	    		}

	    		pred = cb.or(cb.equal(joinExerciseGroupedStep.get(ExerciseGroupedStep_.intensityZone), line.getValue())
    						,cb.equal(joinExerciseStep.get(ExerciseStep_.intensityZone), line.getValue()));

	    		predicateList.add(pred);
	    		
	    	}else if(line.getKey().toString().equals("intensityZones")){

	    		if(joinExerciseGroupedStep == null){
	    			joinExerciseGroupedStep = step.join(Step_.exerciseGroupedStep,JoinType.LEFT);
	    			joinExerciseGroupedStep.alias("ueh");
	    			
	    		}
	    		if(joinExerciseStep == null){
	    			joinExerciseStep = step.join(Step_.exerciseStep,JoinType.LEFT);
	    			joinExerciseGroupedStep.alias("ueh2");

	    		}

	    		pred = cb.or(joinExerciseGroupedStep.get(ExerciseGroupedStep_.intensityZone).in(line.getValue())
    						,joinExerciseStep.get(ExerciseStep_.intensityZone).in(line.getValue()));

	    		predicateList.add(pred);
	    		
	    			    		
	    		
	    	}else if(line.getKey().toString().equals("intensityModZone")){

	    		if(joinTemplate == null){
	    			joinTemplate = step.join(Step_.templateExercise,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseGroupStep == null){
	    			joinExerciseGroupStep = step.join(Step_.exerciseGroupStep,JoinType.LEFT);
	    		}


	    		pred = cb.or(cb.equal(joinTemplate.get(TemplateExercise_.intensityModZone), line.getValue())
    						,cb.equal(joinExerciseGroupStep.get(ExerciseGroupStep_.intensityModZone), line.getValue()));

	    		predicateList.add(pred);
	    		
	    		
	    	}else if(line.getKey().toString().equals("volumeType")){

	    		if(joinExerciseGroupedStep == null){
	    			joinExerciseGroupedStep = step.join(Step_.exerciseGroupedStep,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseStep == null){
	    			joinExerciseStep = step.join(Step_.exerciseStep,JoinType.LEFT);
	    		}
	    		

	    		if(joinTemplate == null){
	    			joinTemplate = step.join(Step_.templateExercise,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseGroupStep == null){
	    			joinExerciseGroupStep = step.join(Step_.exerciseGroupStep,JoinType.LEFT);
	    		}
	    		
	    		
	    		pred = cb.or(cb.equal(joinExerciseStep.get(ExerciseStep_.volumeType), line.getValue())
    						,cb.equal(joinTemplate.get(TemplateExercise_.volumeType), line.getValue())
    						,cb.equal(joinExerciseGroupStep.get(ExerciseGroupStep_.volumeType), line.getValue()));

	    		predicateList.add(pred);	    		
	    		
	    		
	    	}else if(line.getKey().toString().equals("execution")){

	    		if(joinExerciseGroupedStep == null){
	    			joinExerciseGroupedStep = step.join(Step_.exerciseGroupedStep,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseStep == null){
	    			joinExerciseStep = step.join(Step_.exerciseStep,JoinType.LEFT);
	    		}
	    		

	    		if(joinTemplate == null){
	    			joinTemplate = step.join(Step_.templateExercise,JoinType.LEFT);
	    			
	    		}
	    		if(joinExerciseGroupStep == null){
	    			joinExerciseGroupStep = step.join(Step_.exerciseGroupStep,JoinType.LEFT);
	    		}
	    		
	    		
	    		pred = cb.or(cb.equal(joinExerciseStep.get(ExerciseStep_.execution), line.getValue())
    						,cb.equal(joinTemplate.get(TemplateExercise_.execution), line.getValue())
    						,cb.equal(joinExerciseGroupStep.get(ExerciseGroupStep_.execution), line.getValue()));

	    		predicateList.add(pred);	    	    		
	    		
	    	}
    	
	    }
	    
	    Predicate[] predicates = new Predicate[predicateList.size()];
	    predicateList.toArray(predicates);
	    cq.where(predicates);
	 
	    
	    return super.getEntityManager().createQuery(cq).getResultList();
	}
	
	
	
	
	
}
